package com.lyn.plugin.annotation

import com.lyn.plugin.other.AnnotationScanResult
import org.objectweb.asm.AnnotationVisitor
import org.objectweb.asm.ClassVisitor
import org.objectweb.asm.ClassWriter
import org.objectweb.asm.Opcodes
import java.io.File

/**
 *
 * @author longyn 2025/07/05
 * @version 1.0.0
 */
class AnnotationClassVisitor(private val generatedOutputFile: File, private val intermediatesOutputFile:File, cv: ClassVisitor) :
    ClassVisitor(Opcodes.ASM9, cv) {


    override fun visitAnnotation(descriptor: String?, visible: Boolean): AnnotationVisitor {
        val visitAnnotation = super.visitAnnotation(descriptor, visible)
        if (descriptor?.contains("PluginLauncher") == false) {
            return visitAnnotation
        }
        return object : AnnotationVisitor(Opcodes.ASM9, visitAnnotation) {
            override fun visit(name: String?, value: Any?) {
                when (name) {
                    "id" -> {
                        value?.let {
                            AnnotationScanResult.PLUGIN_ID = it.toString()
                        }
                    }

                    "name" -> {
                        value?.let {
                            AnnotationScanResult.PLUGIN_NAME = it.toString()
                        }
                    }

                    "version" -> {
                        value?.let {
                            AnnotationScanResult.PLUGIN_VERSION = it as Int
                        }
                    }
                }
                val javaCode = """
        package com.lyn.pluginapi;

        public final class PluginConfig {
            public static final String PLUGIN_ID = "${AnnotationScanResult.PLUGIN_ID}";
            public static final String PLUGIN_NAME = "${AnnotationScanResult.PLUGIN_NAME}";
            public static final String PLUGIN_LAUNCHER_CLASS_NAME = "${AnnotationScanResult.PLUGIN_LAUNCHER_CLASS_NAME}";
            public static final int PLUGIN_VERSION = ${AnnotationScanResult.PLUGIN_VERSION};
        }
    """.trimIndent()

                val generatedTargetFile = File(generatedOutputFile, "com/lyn/pluginapi/PluginConfig.java")
                generatedTargetFile.parentFile.mkdirs()
                generatedTargetFile.createNewFile()
                generatedTargetFile.writeText(javaCode)
                println("> Task :[AndPlugin]:GenerateClass:${generatedTargetFile.absolutePath}")
                val intermediatesTargetFile = File(intermediatesOutputFile, "com/lyn/pluginapi/PluginConfig.class")
                intermediatesTargetFile.parentFile.mkdirs()
                intermediatesTargetFile.createNewFile()
                val intermediatesClassBytes = generateClass("com.lyn.pluginapi.PluginConfig")
                intermediatesTargetFile.writeBytes(intermediatesClassBytes)
                super.visit(name, value)
            }
        }
    }

    fun generateClass(className: String): ByteArray {
        val classWriter = ClassWriter(Opcodes.ASM9)
        classWriter.visit(
            Opcodes.ASM9,
            Opcodes.ACC_PUBLIC or Opcodes.ACC_SUPER or Opcodes.ACC_FINAL,
            className.replace('.', '/'),
            null,
            "java/lang/Object", null
        )
        var vf = classWriter.visitField(
            Opcodes.ACC_PUBLIC or Opcodes.ACC_STATIC or Opcodes.ACC_FINAL,
            "PLUGIN_ID",
            "Ljava/lang/String;",
            null, AnnotationScanResult.PLUGIN_ID
        )
        vf.visitEnd()
        vf = classWriter.visitField(
            Opcodes.ACC_PUBLIC or Opcodes.ACC_STATIC or Opcodes.ACC_FINAL,
            "PLUGIN_NAME",
            "Ljava/lang/String;",
            null, AnnotationScanResult.PLUGIN_NAME
        )
        vf.visitEnd()
        vf = classWriter.visitField(
            Opcodes.ACC_PUBLIC or Opcodes.ACC_STATIC or Opcodes.ACC_FINAL,
            "PLUGIN_LAUNCHER_CLASS_NAME",
            "Ljava/lang/String;",
            null, AnnotationScanResult.PLUGIN_LAUNCHER_CLASS_NAME
        )
        vf.visitEnd()
        vf = classWriter.visitField(
            Opcodes.ACC_PUBLIC or Opcodes.ACC_STATIC or Opcodes.ACC_FINAL,
            "PLUGIN_VERSION",
            "I",
            null, AnnotationScanResult.PLUGIN_VERSION
        )
        vf.visitEnd()
        classWriter.visitEnd()
        return classWriter.toByteArray()
    }


}